﻿using System;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
using ZCUtil.Touch;
using ZCUIManager;
using ZCUtil.Factory;

namespace ZCTouchDrawBoard
{
    [Serializable]
    public abstract class BasePaperView : UIBaseView,
        IPointerDownHandler,
        IPointerUpHandler,
        IPointerClickHandler,
        IDragHandler
    {
        #region ProtectedField
        /// <summary>
        /// 贝塞尔曲线
        /// </summary>
        protected static TouchPoint m_PaintTouch = new TouchPoint();

        /// <summary>
        /// 宽度
        /// </summary>
        [SerializeField] protected int m_Width;

        /// <summary>
        /// 高度
        /// </summary>
        [SerializeField] protected int m_Height;

        /// <summary>
        /// 深度
        /// </summary>
        [SerializeField] protected int m_Depth;

        /// <summary>
        /// 纹理
        /// </summary>
        [SerializeField] protected RenderTexture m_RenderTexture;

        /// <summary>
        /// 纹理大小
        /// </summary>
        [SerializeField] protected Vector2Int m_RenderTextureSize;

        /// <summary>
        /// 正交投影
        /// </summary>
        [SerializeField] protected Matrix4x4 m_OrthoMatrix;

        /// <summary>
        /// 是否编辑
        /// </summary>
        [SerializeField] protected bool m_Editing = false;

        /// <summary>
        /// 是否Touch
        /// </summary>
        [SerializeField] protected bool m_IsTouch = false;

        /// <summary>
        /// 是否拖动
        /// </summary>
        [SerializeField] protected bool m_IsDrag = false;

        protected TouchDrawingView m_TouchDrawingView;
        protected PaperPanel m_PaperPanel;
        protected PaintPanel m_PaintPanel;
        #endregion

        #region PublicMethod
        public static TouchPoint TouchPoint => m_PaintTouch;

        public override bool isUIView => false;

        public int Width => m_Width;

        public int Height => m_Height;

        public virtual RenderTexture RenderTexture => m_RenderTexture;

        public virtual RectTransform RectTransform => m_RectTransform;

        public virtual bool Editing 
        {
            get
            {
                return m_Editing;
            }
            set
            {
                m_Editing = value;
            }
        }

        public virtual TouchDrawingView TouchDrawingView
        {
            get
            {
                return m_TouchDrawingView;
            }
            set
            {
                if (m_TouchDrawingView == value)
                {
                    return;
                }
                m_TouchDrawingView = value;
                m_PaperPanel = m_TouchDrawingView.PaperPanel;
                m_PaintPanel = m_TouchDrawingView.PaintPanel;
            }
        }

        public virtual PaperPanel PaperPanel => m_PaperPanel;

        public virtual PaintPanel PaintPanel => m_PaintPanel;

        public virtual Matrix4x4 OrthoMatrix => m_OrthoMatrix;
        #endregion

        #region Graphic Override Method
        /// <summary>
        /// 重写mainTexture
        /// </summary>
        public override Texture mainTexture
        {
            get
            {
                if (RenderTexture == null)
                {
                    return base.mainTexture;
                }
                return RenderTexture;
            }
        }

        /// <summary>
        /// 重写OnPopulateMesh
        /// </summary>
        /// <param name="vh"></param>
        protected override void OnPopulateMesh(VertexHelper vh)
        {
            Texture tex = mainTexture;
            vh.Clear();
            if (tex != null)
            {
                var r = GetPixelAdjustedRect();
                var v = new Vector4(r.x, r.y, r.x + r.width, r.y + r.height);
                var scaleX = tex.width * tex.texelSize.x;
                var scaleY = tex.height * tex.texelSize.y;
                {
                    var color32 = color;
                    vh.AddVert(new Vector3(v.x, v.y), color32, new Vector2(0, 0));
                    vh.AddVert(new Vector3(v.x, v.w), color32, new Vector2(0, scaleY));
                    vh.AddVert(new Vector3(v.z, v.w), color32, new Vector2(scaleX, scaleY));
                    vh.AddVert(new Vector3(v.z, v.y), color32, new Vector2(scaleX, 0));

                    vh.AddTriangle(0, 1, 2);
                    vh.AddTriangle(2, 3, 0);
                }
            }
        }
        #endregion

        #region PublicMethod
        /// <summary>
        /// 初始化Paper, 抛出异常(此方法用于多态)
        /// </summary>
        /// <param name="width"></param>
        /// <param name="height"></param>
        /// <param name="depth"></param>
        public virtual void Initialize(int width, int height, int depth = 16)
        {
            throw new System.Exception("base paper not impl.");
        }

        /// <summary>
        /// 初始化Paper, 创建RT
        /// </summary>
        /// <param name="width"></param>
        /// <param name="height"></param>
        /// <param name="depth"></param>
        /// <param name="format"></param>
        /// <param name="textureNumber"></param>
        public virtual void Initialize(int width, int height, int depth, RenderTextureFormat format, int textureNumber)
        {
            // 初始化
            m_RectTransform.anchoredPosition = Vector2.zero;
            m_RectTransform.sizeDelta = new Vector2(width, height);
            m_Width = width;
            m_Height = height;
            m_Depth = depth;
            // 清除
            if (m_RenderTexture != null)
            {
                Release();
            }
            // 计算2的幂次
            int length = width * height;
            int pow = 0;
            while (length > 2)
            {
                length >>= 2;
                pow++;
            }
            // 计算大小, 并创建RT
            m_RenderTextureSize = new Vector2Int(2 << pow, 2 << pow);
            m_RenderTexture = RenderTexture.GetTemporary(m_RenderTextureSize.x, m_RenderTextureSize.y, depth, format);
            Clear();
            // 计算正交矩阵和缩放矩阵
            width /= 2;
            height /= 2;
            m_OrthoMatrix = Matrix4x4.Ortho(-width, width, -height, height, -1, 1);
        }

        /// <summary>
        /// 使用Paper
        /// </summary>
        public virtual void Use()
        {
            Graphics.SetRenderTarget(m_RenderTexture);
        }

        /// <summary>
        /// 更新Paper显示内容
        /// </summary>
        public virtual void Display()
        {
            SetVerticesDirty();
        }

        /// <summary>
        /// 清理Paper显示内容
        /// </summary>
        public virtual void Clear()
        {

        }

        /// <summary>
        /// 释放RT
        /// </summary>
        public virtual void Release()
        {
            if (m_RenderTexture == null)
            {
                return;
            }
            RenderTexture.ReleaseTemporary(m_RenderTexture);
        }
        #endregion

        #region Drawing
        /// <summary>
        /// 点击事件
        /// </summary>
        /// <param name="eventData"></param>
        public virtual void OnPointerClick(PointerEventData eventData)
        {
            if (Editing)
            {
                // 编辑状态控制权是自己的
            }
            else
            {
                // 内部自己切换
                PaperPanel.SwitchPaper(gameObject);
            }
            // 控制权交给上层
            PaperPanel?.ClickPaperCallback?.Invoke(gameObject, eventData);
        }

        /// <summary>
        /// 按下事件
        /// </summary>
        /// <param name="eventData"></param>
        public virtual void OnPointerDown(PointerEventData eventData)
        {
            m_IsTouch = true;
            if (Editing)
            {
                // 编辑状态控制权是自己的
                RectTransformUtility.ScreenPointToLocalPointInRectangle(m_RectTransform, eventData.position, Camera.main, out Vector2 position);
                m_PaintTouch.SetPoint(position);
                PaintPanel.SelectPaint.DrawToPaper(m_PaintTouch, this, ePaintEvent.Down, MeshFactory.GetMesh(eMeshType.ZC_QUAD));
                m_PaintTouch.Clear();
            }
            PaperPanel?.ClickDownPaperCallback?.Invoke(gameObject, eventData);
        }

        /// <summary>
        /// 拖拽事件
        /// </summary>
        /// <param name="eventData"></param>
        public virtual void OnDrag(PointerEventData eventData)
        {
            m_IsDrag = true;
            if (Editing)
            {
                // 编辑状态控制权是自己的
                RectTransformUtility.ScreenPointToLocalPointInRectangle(m_RectTransform, eventData.position, Camera.main, out Vector2 position);
                m_PaintTouch.SetPoint(position);
                PaintPanel.SelectPaint.DrawToPaper(m_PaintTouch, this, ePaintEvent.Drag, MeshFactory.GetMesh(eMeshType.ZC_QUAD));
                m_PaintTouch.Clear();
            }
            // 控制权交给上层
            PaperPanel?.DragPaperCallback?.Invoke(gameObject, eventData, Editing);
        }

        /// <summary>
        /// 弹起事件
        /// </summary>
        /// <param name="eventData"></param>
        public virtual void OnPointerUp(PointerEventData eventData)
        {
            if (Editing)
            {
                // 编辑状态控制权是自己的
                RectTransformUtility.ScreenPointToLocalPointInRectangle(m_RectTransform, eventData.position, Camera.main, out Vector2 position);
                m_PaintTouch.SetPoint(position);
                PaintPanel.SelectPaint.DrawToPaper(m_PaintTouch, this, ePaintEvent.Up, MeshFactory.GetMesh(eMeshType.ZC_QUAD));
                m_PaintTouch.Clear();
            }
            PaperPanel?.ClickUpPaperCallback?.Invoke(gameObject, eventData);

            m_IsTouch = false;
            m_IsDrag = false;
            m_PaintTouch.DropTouch();
        }
        #endregion
    }
}
